package com.cooler.floatview;

import java.io.IOException;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.LinearLayout;

@SuppressLint("HandlerLeak")
public class FloatService extends Service
{
	private static final String TAG = "Vtag";
	private static final int SWITCH_CAMERA = 0x01;
	private static final int SWITCH_COMPLETE = 0x02;
	private int mCameraPosition = 0;
	
	private WindowManager mWindowManager;
	private WindowManager.LayoutParams mWindowParams;
	private LinearLayout mFloatLayout;
	private SurfaceView mFloatCameraView;
	private Camera mCamera = null;
	private SurfaceHolder mSurfaceHolder;
	
	/* the x and y coordinate of current touch point */
	private int mX, mY;
	
	private final Messenger mMessenger = new Messenger(new Handler(){
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == SWITCH_CAMERA) {
				try {
					msg.replyTo.send(Message.obtain(
							null, SWITCH_COMPLETE, mCameraPosition, 0));
					Log.d(TAG, "message from client: " + msg.arg1);
					switchCamera();
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				super.handleMessage(msg);
			}
		}
	});
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		boolean result = CameraHardware.checkCameraHardware(getApplicationContext());
		Log.d(TAG, "[camera check result]: " + result);
		
		if (result == true) {
			mCamera = CameraHardware.openCamera();
			if (mCamera != null) {
				Log.d(TAG, "[camera opened]: " + mCamera.getParameters());
			} else {
				Log.d(TAG, "fail to open camera");
			}
		}
		
		createFloatView();
		Log.d(TAG, "the float window created");
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return mMessenger.getBinder();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		
		if (mFloatLayout != null) {
			mWindowManager.removeView(mFloatLayout);
		}
	}
	
	private class holderCallback implements SurfaceHolder.Callback {
		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, 
				int width, int height) {
			if (mCamera != null) {
				mCamera.stopPreview();
				mCamera.setDisplayOrientation(90);
				mCamera.startPreview();
			}
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			try {
				mCamera.setPreviewDisplay(holder);
				mCamera.startPreview();
			} catch (IOException e) {
				Log.d(TAG, "[Error setting camera preview]: " + e.getMessage());
			}
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			if (mCamera != null) {
				mCamera.stopPreview();
				mCamera.release();
				mCamera = null;
				Log.d(TAG, "camera released");
			}
		}
	}
	
	/**
	 * Create the float view.
	 */
	private void createFloatView() {
		mWindowParams = new WindowManager.LayoutParams();
		mWindowManager = (WindowManager) getApplication()
				.getSystemService(Context.WINDOW_SERVICE);

		mWindowParams.type = LayoutParams.TYPE_PHONE;
		mWindowParams.format = PixelFormat.RGBA_8888;
		mWindowParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;
		mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
		mWindowParams.x = 0;
		mWindowParams.y = 0;
		mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
		mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
		
		LayoutInflater inflater = LayoutInflater.from(getApplication());

		/* get the root of float view */
		mFloatLayout = (LinearLayout) inflater.inflate(R.layout.layout_float_view, null);
		mWindowManager.addView(mFloatLayout, mWindowParams);

		/* get the float view */
		mFloatCameraView = (SurfaceView) mFloatLayout.findViewById(R.id.camera_view);

		mFloatLayout.measure(View.MeasureSpec
				.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), 
				View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

		/* set the callback for surface holder */
		mSurfaceHolder = mFloatCameraView.getHolder();
		mSurfaceHolder.addCallback(new holderCallback());
		
		mFloatCameraView.setOnTouchListener(new View.OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event){
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					mX = (int) event.getX();
					mY = (int) event.getY();
					break;
				
				case MotionEvent.ACTION_MOVE:
					refreshView((int) event.getRawX() - mX, 
							(int) event.getRawY() - mY);
					break;
					
				default:
					break;
				}
				
				return true;
			}
		});
	}
	
	/**
	 * refresh the view according to the coordinate.
	 * 
	 * @param x the x of coordinate
	 * @param y the y of coordinate
	 */
	private void refreshView(int x, int y) {
		this.mWindowParams.x = x;
		this.mWindowParams.y = y;
		this.mWindowManager.updateViewLayout(mFloatLayout, mWindowParams);
	}
	
	private void switchCamera() {
		CameraInfo cameraInfo = new CameraInfo();
		int cameraNum = Camera.getNumberOfCameras();
		
		for (int i = 0; i < cameraNum; i ++) {
			Camera.getCameraInfo(i, cameraInfo);
			
			if (mCameraPosition == 0) {
				if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
					mCamera.stopPreview();
					mCamera.release();
					mCamera = null;
				
					mCamera = Camera.open(i);
					try {
						mCamera.setDisplayOrientation(90);
						mCamera.setPreviewDisplay(mSurfaceHolder);
					} catch (Exception e) {
						e.printStackTrace();
					}
					mCamera.startPreview();
					mCameraPosition = 1;
					break;
				} 
			} else {
				if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
					mCamera.stopPreview();
					mCamera.release();
					mCamera = null;
						
					mCamera = Camera.open(i);
					try {
						mCamera.setDisplayOrientation(90);
						mCamera.setPreviewDisplay(mSurfaceHolder);
					} catch (Exception e) {
						e.printStackTrace();
					}
					mCamera.startPreview();
					mCameraPosition = 0;
					break;
				}
			}
		}
	}
}
